package com.ywk.springCore.lifeCycle.core;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 操作 bean 范围：BeanNameAware（当前bean） < BeanFactoryAware（全部bean） < ApplicationContextAware（spring容器）
 * 执行顺序：BeanNameAware -> BeanFactoryAware -> ApplicationContextAware；
 *
 * 对当前Bean进行销毁前的处理：DisposableBean
 *
 * @Author zbh
 * @Date 2023/4/12
 */
@Data
@Component
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, DisposableBean {

    /**
     * @Value 属性注入是在实例化后初始化前注入的
     */
    @Value("${student.id}")
    private Integer id;
    @Value("${student.name}")
    private String name;

    /**
     * @Autowired 属性注入是在实例化后初始化前注入的
     */
    @Autowired
    Card card;

    //需要对beanFactory或applicationContext修改也可通过@Autowired方式注入来修改
    /*@Autowired
    BeanFactory beanFactory;

    @Autowired
    ApplicationContext applicationContext;*/

    public Student(){
        log.info("实例化：{}",this);
    }

    public Student(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    /*
    * 使用 BeanNameAware 接口，可以对当前 Bean进行操作，
    * setBeanName 执行时机：实例化后，@Value/@Autowire等方式属性注入后，初始化前的。
    *
    * */
    @Override
    public void setBeanName(String name) {
        log.info("执行 BeanNameAware.setBeanName前{}",this);
        log.info("通过 BeanNameAware.setBeanName获取 student,进行student属性值的修改");
        this.id = 2;
        this.name = "b";
        log.info("执行 BeanNameAware.setBeanName后{}",this);
    }

    /**
     * 使用 BeanFactoryAware 接口，可以在setBeanFactory方法中获取、修改 beanFactory中的所有bean，操作范围比 BeanNameAware 大
     *
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

        log.info("执行 BeanFactoryAware.setBeanFactory 前{}",this);
        log.info("通过 beanFactory 获取 card，进行card属性值的修改");
        Card card = beanFactory.getBean("card", Card.class);
        card.setId(3);
        log.info("执行 BeanFactoryAware.setBeanFactory 后",this);

    }

    /**
     * 使用 ApplicationContextAware 接口，可以在该方法中对Spring容器进行设置，操作的范围又要比 BeanFactoryAware的setBeanFactory 大
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        log.info("执行 ApplicationContextAware.setApplicationContext 前",this);
        log.info("通过 ApplicationContext 容器获取 card，进行card属性值的修改");
        Card card = applicationContext.getBean("card", Card.class);
        card.setId(4);
        log.info("执行 ApplicationContextAware.setApplicationContext 后{}",this);
        /*此时 spring 容器中还未注入 studentService，所以通过容器获取不到 studentService，就会进行studentService在spring中的注入流程
        （即提前了studentService的注入）*/
//        StudentService studentService = applicationContext.getBean("studentService",StudentService.class);
        /*AutowireCapableBeanFactory capableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
        capableBeanFactory.destroyBean(card);*/
        //注：虽然这里使用destroyBean来销毁了Card bean，如果又通过getBean来获取Card bean，则会重新创建Card bean。
//        Card c = applicationContext.getBean("card", Card.class);
    }


    /**
     * 对单独的Bean进行销毁前的处理
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        log.info("执行 DisposableBean.destroy对{}",this+"进行销毁前的处理");
    }
}
